package com.ushine.web.communication.signature.custom;

import com.google.common.collect.Lists;
import com.ushine.web.communication.signature.SignatureHeaders;
import com.ushine.web.component.http.HttpResponseVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @Author: yls
 * @Date: 2021/12/16 17:01
 * @Description:
 * @Version 1.0
 */
@Slf4j
@Component
public class SignatureServer {

    private static final String POST = "post";
    private static final String GET = "get";

    public HttpResponseVO verifySignature(ServerHttpRequest request, SignatureHeaders signatureHeaders) {
        //客户端签名
        String clientSignature = signatureHeaders.getSignature();
        log.info("获取客户端签名：" + clientSignature);
        //服务端签名
        String serverSignature = "";
        HttpMethod method = request.getMethod();
        if (POST.equalsIgnoreCase(method.toString())) {
            Map<String, Object> requestParamMap = new HashMap<>();
            request.getQueryParams().forEach((k, v) -> {
                log.info("param:" + k + ":" + v);
                requestParamMap.put(k, v);
            });
            request.getHeaders().forEach((k, v) -> {
                log.info("head:" + k + ":" + v);
            });
            serverSignature = SignatureUtils.signature(signatureHeaders, null, requestParamMap, null);
            log.info("获取服务端端签名：" + clientSignature);
        } else if (GET.equalsIgnoreCase(method.toString())) {
            String path = request.getURI().getPath();
            List<String> pathParams = new ArrayList<>();
            pathParams.add(path);
            serverSignature = SignatureUtils.signature(signatureHeaders, pathParams, null, null);
        }

        if (!clientSignature.equals(serverSignature)) {
            String errMsg = String.format("签名不一致... clientSignature=%s, serverSignature=%s", clientSignature, serverSignature);
            return new HttpResponseVO<>().error(errMsg);
        }
        String successMsg = "签名验证通过, 相关信息：客户端签名=" + clientSignature + "，服务端签名=" + serverSignature;
        return new HttpResponseVO<>().ok(successMsg);
    }

    /**
     * 功能描述:
     * 〈生成header中的参数，mehtod中的参数的拼接〉
     *
     * @param method          对应的方法
     * @param args            参数
     * @param headersToSplice 头部拼接信息
     * @return : java.util.List<java.lang.String>
     * @author : yls
     * @date : 2021/12/21 9:25
     */
    private List<String> generateAllSplice(Method method, Object[] args, String headersToSplice) {
        List<String> pathVariables = Lists.newArrayList();
        List<String> requestParams = Lists.newArrayList();
        String beanParams = StringUtils.EMPTY;
        for (int i = 0; i < method.getParameterCount(); ++i) {
            MethodParameter mp = new MethodParameter(method, i);
            boolean findSignature = false;
            for (Annotation anno : mp.getParameterAnnotations()) {
                if (anno instanceof PathVariable) {
                    if (!Objects.isNull(args[i])) {
                        pathVariables.add(args[i].toString());
                    }
                    findSignature = true;
                } else if (anno instanceof RequestParam) {
                    RequestParam rp = (RequestParam) anno;
                    String name = mp.getParameterName();
                    if (StringUtils.isNotBlank(rp.name())) {
                        name = rp.name();
                    }
                    if (!Objects.isNull(args[i])) {
                        List<String> values = Lists.newArrayList();
                        if (args[i].getClass().isArray()) {
                            //数组
                            for (int j = 0; j < Array.getLength(args[i]); ++j) {
                                values.add(Array.get(args[i], j).toString());
                            }
                        } else if (ClassUtils.isAssignable(Collection.class, args[i].getClass())) {
                            //集合
                            for (Object o : (Collection<?>) args[i]) {
                                values.add(o.toString());
                            }
                        } else {
                            //单个值
                            values.add(args[i].toString());
                        }
                        values.sort(Comparator.naturalOrder());
                        requestParams.add(name + "=" + StringUtils.join(values));
                    }
                    findSignature = true;
                } else if (anno instanceof RequestBody || anno instanceof ModelAttribute) {
                    beanParams = SignatureUtils.toSplice(args[i]);
                    findSignature = true;
                }

                if (findSignature) {
                    break;
                }
            }
            if (!findSignature) {
                log.info(String.format("签名未识别的注解, method=%s, parameter=%s, annotations=%s", method.getName(), mp.getParameterName(), StringUtils.join(mp.getMethodAnnotations())));
            }
        }
        List<String> toSplices = Lists.newArrayList();
        toSplices.add(headersToSplice);
        toSplices.addAll(pathVariables);
        requestParams.sort(Comparator.naturalOrder());
        toSplices.addAll(requestParams);
        toSplices.add(beanParams);
        return toSplices;
    }

}



